﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Drawing.Imaging;

namespace LowLevelGraphics.Filter
{
    /// <summary>
    /// Photoshop Fillmode
    /// </summary>
    public class WeichesLicht : BaseImageFilter, ITwoSourceFilter
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="WeichesLicht"/> class.
        /// </summary>
        public WeichesLicht()
        {
        }

        /// <summary>
        /// Execute this Filter
        /// A Debug Statement is written if a concrete Filter is called
        /// </summary>
        /// <param name="_bitmap"></param>
        /// <returns></returns>
        public override UnsafeBitmap Execute(UnsafeBitmap _bitmap)
        {
            Process((UnsafeBitmap)_bitmap.Clone(), _bitmap);
            return _bitmap;
        }

        #region ITwoSourceFilter Members

        /// <summary>
        /// Processes the specified _bitmap source.
        /// </summary>
        /// <param name="_bitmapSource">The _bitmap source.</param>
        /// <param name="_bitmapDest">The _bitmap dest.</param>
        /// <returns></returns>
        public UnsafeBitmap Process(UnsafeBitmap _bitmapSource, UnsafeBitmap _bitmapDest)
        {
            UnsafeBitmap bitmapSource = _bitmapSource;
            UnsafeBitmap bitmapDest = _bitmapDest;

            Color colorSource = Color.Transparent;
            Color colorDest = Color.Transparent;

            int y = 0;
            int x = 0;

            int nHeight = bitmapSource.Height;
            int nWidth = bitmapSource.Width;

            int nRSource = 0;
            int nGSource = 0;
            int nBSource = 0;

            int nRDest = 0;
            int nGDest = 0;
            int nBDest = 0;

            double dRResult = 0;
            double dGResult = 0;
            double dBResult = 0;

            double dRFirst = 0;
            double dGFirst = 0;
            double dBFirst = 0;

            for (y = 0; y < nHeight; y++)
            {
                for (x = 0; x < nWidth; x++)
                {
                    colorSource = bitmapSource.GetPixel(x, y);
                    colorDest = bitmapDest.GetPixel(x, y);

                    nRSource = colorDest.R;
                    nGDest = colorDest.G;
                    nBDest = colorDest.B;

                    nRDest = colorSource.R;
                    nGSource = colorSource.G;
                    nBSource = colorSource.B;

                    //2*A-1
                    dRFirst = nRSource * 2 - 255;
                    dGFirst = nGSource * 2 - 255;
                    dBFirst = nBSource * 2 - 255;


                    //What do neagtive values mean here?
                    if (nRSource <= 127 && nGSource <= 127 && nBSource <= 127)
                    {
                        //(2*A-1) * (B-B²)
                        dRResult = dRFirst * (nRDest - nRDest * nRDest);
                        dGResult = dGFirst * (nGDest - nGDest * nGDest);
                        dBResult = dBFirst * (nBDest - nBDest * nBDest);
                    }
                    else
                    {
                        //(2*A-1) * (Sqrt(B)-B)
                        dRResult = dRFirst * (Math.Sqrt(nRDest) - nRDest);
                        dGResult = dGFirst * (Math.Sqrt(nGDest) - nGDest);
                        dBResult = dBFirst * (Math.Sqrt(nBDest) - nBDest);
                    }

                    //+B
                    dRResult += nRDest;
                    dGResult += nGDest;
                    dBResult += nBDest;

                    //So we did a 
                    //(2*A-1)*(B-B²)+B if A<=0.5
                    //else
                    //(2*A-1)*(Sqrt(B)-B)+B if A>0.5

                    if (dRResult < 0) dRResult = 0;
                    if (dGResult < 0) dGResult = 0;
                    if (dBResult < 0) dBResult = 0;
                    if (dRResult > 255) dRResult = 255;
                    if (dGResult > 255) dGResult = 255;
                    if (dBResult > 255) dBResult = 255;
                    
                    colorDest = Color.FromArgb((int)dRResult, (int)dGResult, (int)dBResult);
                    bitmapDest.SetPixel(x, y, colorDest);
                }
            }
            bitmapSource.Dispose();
            bitmapDest.Dispose();
            return _bitmapDest;
        }

        #endregion

        /// <summary>
        /// This is used to clone a filter, each filter must implement it's own clone functionality
        /// </summary>
        /// <returns></returns>
        public override object Clone()
        {
            return new WeichesLicht();
        }
    }
}
